using System.Collections.Generic;
using Castle.ActiveRecord;
using NHibernate.Expression;

namespace Project.Library.ActiveRecord.Repositories
{
    /// <summary>
    /// Base type repository
    /// Provide the basic operations on the database.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ActiveRecordRepository<T> : IActiveRecordRepository<T> where T : class
    {
        public bool UseAutoFlush{ get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="ActiveRecordRepository&lt;T&gt;"/> class.
        /// </summary>
        public ActiveRecordRepository()
        {
            // default behavior
            UseAutoFlush = false;
        }

        #region Exists

        /// <summary>
        /// Existses the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        public virtual bool Exists(T entity)
        {
            return ActiveRecordMediator<T>.Exists(entity);
        }

        /// <summary>
        /// Existses the specified where.
        /// </summary>
        /// <param name="where">The where.</param>
        /// <returns></returns>
        public virtual bool Exists(DetachedCriteria where)
        {
            return ActiveRecordMediator<T>.Exists(where);
        }

        /// <summary>
        /// Existses the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public virtual bool Exists(object id)
        {
            return ActiveRecordMediator<T>.Exists(id);
        }

        #endregion

        #region Count

        /// <summary>
        /// Counts this instance.
        /// </summary>
        /// <returns></returns>
        public virtual int Count()
        {
            return ActiveRecordMediator<T>.Count();
        }

        /// <summary>
        /// Counts the specified where.
        /// </summary>
        /// <param name="where">The where.</param>
        /// <returns></returns>
        public virtual int Count(DetachedCriteria where)
        {
            return ActiveRecordMediator<T>.Count(where);
        }

        #endregion

        #region Search

        /// <summary>
        /// Finds all.
        /// </summary>
        /// <returns></returns>
        public virtual IList<T> FindAll()
        {
            return ActiveRecordMediator<T>.FindAll();
        }

        /// <summary>
        /// Finds all.
        /// </summary>
        /// <param name="where">The where.</param>
        /// <returns></returns>
        public virtual IList<T> FindAll(DetachedCriteria where)
        {
            return ActiveRecordMediator<T>.FindAll(where);
        }

        /// <summary>
        /// Finds all.
        /// </summary>
        /// <param name="firstResult">The first result.</param>
        /// <param name="maxResult">The max result.</param>
        /// <param name="where">The where.</param>
        /// <returns></returns>
        public virtual IList<T> FindAll(int firstResult, int maxResult, DetachedCriteria where)
        {
            return ActiveRecordMediator<T>.SlicedFindAll(firstResult, maxResult, where);
        }

        /// <summary>
        /// Gets the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public virtual T Get(object id)
        {
            return ActiveRecordMediator<T>.FindByPrimaryKey(id, false);
        }

        /// <summary>
        /// Loads the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public virtual T Load(object id)
        {
            return ActiveRecordMediator<T>.FindByPrimaryKey(id, true);
        }

        /// <summary>
        /// Finds the first.
        /// </summary>
        /// <param name="where">The where.</param>
        /// <returns></returns>
        public virtual T FindFirst(DetachedCriteria where)
        {
            return ActiveRecordMediator<T>.FindFirst(where);
        }

        /// <summary>
        /// Finds the first.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <returns></returns>
        public virtual T FindFirst(Order[] order)
        {
            return ActiveRecordMediator<T>.FindFirst(order);
        }

        #endregion       

        #region Perform persistance

        /// <summary>
        /// Saves the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        public virtual T Save(T entity)
        {
            if (UseAutoFlush)
                ActiveRecordMediator.CreateAndFlush(entity);
            else
                ActiveRecordMediator<T>. Create(entity);

            return entity;
        }

        /// <summary>
        /// Updates the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        public virtual T Update(T entity)
        {
            if (UseAutoFlush)
                ActiveRecordMediator.UpdateAndFlush(entity);
            else
                ActiveRecordMediator<T>.Update(entity);

            return entity;
        }

        /// <summary>
        /// Saves the or update.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns></returns>
        public virtual T SaveOrUpdate(T entity)
        {
            if(UseAutoFlush)
                ActiveRecordMediator.SaveAndFlush(entity);
            else
                ActiveRecordMediator<T>.Save(entity);

            return entity;
        }

        /// <summary>
        /// Deletes the specified entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        public virtual void Delete(T entity)
        {
            if(UseAutoFlush)
                ActiveRecordMediator.DeleteAndFlush(entity);
            else
                ActiveRecordMediator<T>.Delete(entity);
        }

        /// <summary>
        /// Deletes all.
        /// </summary>
        public virtual void DeleteAll()
        {
            ActiveRecordMediator<T>.DeleteAll();
        }

        /// <summary>
        /// Deletes all.
        /// </summary>
        /// <param name="with">The with.</param>
        public virtual void DeleteAll(DetachedCriteria with)
        {
            foreach (var entity in ActiveRecordMediator<T>.FindAll(with))
            {
                Delete(entity);
            }
        }

        #endregion

        #region DetachedCriteria

        /// <summary>
        /// Creates the detached criteria.
        /// </summary>
        /// <returns></returns>
        public DetachedCriteria CreateDetachedCriteria()
        {
            return DetachedCriteria.For<T>();
        }

        /// <summary>
        /// Creates the detached criteria.
        /// </summary>
        /// <param name="alias">The alias.</param>
        /// <returns></returns>
        public DetachedCriteria CreateDetachedCriteria(string alias)
        {
            return DetachedCriteria.For(typeof(T), alias);
        }

        #endregion
    }
}